#!/usr/bin/python

import signal;
import gdb;

pid_list = {};
all_clock = 0;
all_count = 0;
keep_running = 1;

def tfind_entry(num):
	if num < 0:
		tid = gdb.execute("tfind", False, True);
	else:
		tid = gdb.execute("tfind "+str(num), False, True);
	if tid.find(", tracepoint ") < 0:
		return -1;
	tid = tid[tid.find(", tracepoint ") + len(", tracepoint "):];
	return int(tid);

def print_top(comm, num):
	for e in comm:
		print e[0], e[1]["comm"], ":", e[1]["clock"],"(%",float(e[1]["clock"])/float(all_clock)*100,")", float(e[1]["count"]),"(%",float(e[1]["count"])/float(all_count)*100,")";
		if num > 0:
			num -= 1;
			if num <= 0:
				break;

def sigint_handler(num, e):
	global pid_list;
	global all_clock;
	global all_count;
	global keep_running;

	print "Pass", all_clock, "Switch", all_count, "times";
	print "";
	print_top (sorted(pid_list.items(), key=lambda d:d[1]["clock"], reverse=True), 0);

	try:
		s = raw_input('Continue? (yes)')
	except:
		s = 'y'
	if s[0:1] == 'n' or s[0:1] == 'N':
		keep_running = 0;
	

gdb.execute("set pagination off", True, True);

signal.signal(signal.SIGINT, sigint_handler);
signal.siginterrupt(signal.SIGINT, False);

schedule_id = 2;
do_exit_id = 3;

#connect to the gdbframe_pipe
#gdb.execute("target tfile /sys/kernel/debug/gtpframe_pipe");

while keep_running:
	try:
		tid = tfind_entry(-1);
		if tid < 0:
			#raise gdb.error ("Something wrong, drop one entry.");
			break;

		if tid == schedule_id or tid == do_exit_id:
			pid = long(gdb.parse_and_eval("$pid"));
			clock = long(gdb.parse_and_eval("$begin"));
			if pid in pid_list:
				pid_list[pid]["clock"] += clock;
				pid_list[pid]["count"] += 1;
			else:
				pid_list[pid]={};
				pid_list[pid]["clock"] = clock;
				pid_list[pid]["count"] = 1;
				pid_list[pid]["comm"] = str(gdb.parse_and_eval("((struct task_struct *)$current_task)->comm"));
			all_clock += clock;
			all_count += 1;
			if tid == do_exit_id:
				exit_pid = "exited"+str(pid);
				pid_list[exit_pid]={};
				pid_list[exit_pid]["clock"] = pid_list[pid]["clock"];
				pid_list[exit_pid]["count"] = pid_list[pid]["count"];
				pid_list[exit_pid]["comm"] = pid_list[pid]["comm"];
				del(pid_list[pid]);
		else:
			raise gdb.error ("Trace id error.");
	
	except gdb.error, x:
		print("Drop one entry because", x);
	except gdb.MemoryError, x:
		print("Drop one entry because", x);

	#gdb.execute("tfind", False, True);

print "Pass", all_clock, "Switch", all_count, "times";
print "";
print_top (sorted(pid_list.items(), key=lambda d:d[1]["clock"], reverse=True), 0);
